package org.aoao.utils;

import javax.crypto.Cipher;
import java.security.*;
import java.util.Base64;

public class MyRSA {

    // 编码格式 GBK
    private String ENCODE="GBK";

    // 密钥对
    private KeyPair keyPair;
    // 加密实例
    private Cipher cipher;

    // 密文字节码
    private byte[] cipherData;
    //数字签名
    private Signature signature;
    //签名 字节码
    private byte[] signData;

    public MyRSA(){
        this(1024);
    }
    public MyRSA(int keySize){
        try{
            //获取rsa 的 KeyPairGenerator 实例
            KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance("rsa");
            //初始化
            keyPairGenerator.initialize(keySize);//秘钥长度1024位
            //获取 密钥对，存入成员变量
            keyPair=keyPairGenerator.generateKeyPair();
            // 实例化 RSA 加密工具
            cipher=Cipher.getInstance("rsa");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public byte[] getCipherData() {
        return cipherData;
    }

    public Signature getSignature() {
        return signature;
    }

    public byte[] getSignData(byte[] data) {
        return generateSignature(data);
    }
    public byte[] getSignData() {
        return signData;
    }

    public PublicKey getPublicKey(){
        return keyPair.getPublic();
    }



    //对plainText 加密
    public String encrypt(String plainText){
        String cipherText=null;
        try{
            // 初始化为 加密模式，使用 RSA 私钥加密
            cipher.init(Cipher.ENCRYPT_MODE,keyPair.getPrivate(),new SecureRandom());
            // 加密 明文
            cipherData=cipher.doFinal(plainText.getBytes(ENCODE));
            //生成数字签名
            generateSignature();
            // 将加密得到的 字节码数据 编码成 字符串 并返回
            cipherText=base64String(cipherData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cipherText;
    }

    // 对cipherText 解密
    public String decrypt(String cipherText){
        String plainText=null;
        try{
            // 初始化为 解密模式， 使用 RSA 公钥解密
            cipher.init(Cipher.DECRYPT_MODE,keyPair.getPublic(),new SecureRandom());
            // 先对密文 使用base64 解码成字节码， 然后 解密成 明文字节码
            byte[] plainData=cipher.doFinal(base64Bytes(cipherText));
            // 将 明文字节码 生成字符串并返回
            plainText=new String(plainData,ENCODE);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return plainText;
    }

    // 根据data 生成数字签名
    private byte[] generateSignature(byte[] data){
        try {
            signature=Signature.getInstance("MD5withRSA");
            signature.initSign(keyPair.getPrivate());
            signature.update(data);
            return signature.sign();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // 生成数字签名
    private void generateSignature(){
        try {
            signature=Signature.getInstance("MD5withRSA");
            signature.initSign(keyPair.getPrivate());
            signature.update(cipherData);
            signData= signature.sign();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 验证 数字签名
    public boolean verifySign(){
        try {
            // 使用 RSA 公钥 初始化验证
            signature.initVerify(keyPair.getPublic());
            // 使用 密文字节码 更新
            signature.update(cipherData);
            // 验证 签名信息 并返回
            return signature.verify(signData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    // 给定签名数据，数据，公钥，验证
    public boolean verifySign(byte[] signData,byte[] data, PublicKey publicKey){
        try {
            signature=Signature.getInstance("MD5withRSA");
            // 使用 RSA 公钥 初始化验证
            signature.initVerify(publicKey);
            // 使用 密文字节码 更新
            signature.update(data);
            // 验证 签名信息 并返回
            return signature.verify(signData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    //用base64 将字符串text 解码
    private byte[] base64Bytes(String text){
        return Base64.getDecoder().decode(text);
    }
    //用base64 将字节码data 编码
    private String base64String(byte[] data){
        return Base64.getEncoder().encodeToString(data);
    }

    public static void main(String[] args) {
        MyRSA myRSA=new MyRSA();
        String cipherText=myRSA.encrypt("201820109刘张澳");
        String plainText=myRSA.decrypt(cipherText);
        System.out.println(cipherText);
        System.out.println(plainText);
        System.out.println(myRSA.verifySign());
        System.out.println(myRSA.keyPair.getPublic().toString());
    }
}
